#include "PhysicalSystem.h"

CPhysicalSystem::CPhysicalSystem()
{
}

void CPhysicalSystem::TwoObject(CObject* obj1, CObject* obj2, float gameTime, CInput* input)
{
	RECT bond = obj1->GetIntersectBond(obj2);
	// For object 1
	RECT rect1 = obj1->GetBond();
	// Xet truong hop va cham duoi (bottom)
	if ((((rect1.left == bond.left) && (rect1.right != bond.right)) || ((rect1.right == bond.right) && (rect1.left != bond.left)))
		&& (bond.right - bond.left < bond.bottom - bond.top)) // Phai o tren cam doidddddddddddddddddddd
	{
		obj1->SetLastPosition();
		obj1->SetVelocityX(0);
		obj1->SetAccelerationX(0);
		obj1->UpdatePosition(gameTime, input);
	}
	else if (rect1.bottom == bond.bottom)
	{
		obj1->SetLastPosition();
		obj1->SetVelocityY(0);
		D3DXVECTOR2 temp = obj1->GetAcceleration();
		obj1->SetAccelerationY(0);
		obj1->UpdatePosition(gameTime, input);
		obj1->SetAccelerationY(temp.y);
		obj1->SetVelocityY(0);
	}
	else if (rect1.top == bond.top)
	{
		obj1->SetLastPosition();
		obj1->SetVelocityY(0);
	}

	obj1->UpdateAnimation(gameTime, input);
}

void CPhysicalSystem::TwoObject2(CObject* obj1, CObject* obj2, float gameTime, CInput* input)
{
	RECT bond = obj1->GetIntersectBond(obj2);
	// For object 1
	RECT rect1 = obj1->GetBond();
	if ((((rect1.left == bond.left) && (rect1.right != bond.right)) || ((rect1.right == bond.right) && (rect1.left != bond.left)))
		&& (bond.right - bond.left < bond.bottom - bond.top)) // Phai o tren cam doidddddddddddddddddddd
	{
		obj1->m_collisionResponse += D3DXVECTOR2(1000, 0);
	}
	else if (rect1.bottom == bond.bottom)
	{
		obj1->m_collisionResponse += D3DXVECTOR2(0, -1000);
	}
	else if (rect1.top == bond.top)
	{
		obj1->SetLastPosition();
		obj1->SetVelocityY(0);
	}

	obj1->UpdateAnimation(gameTime, input);
}

bool CPhysicalSystem::AABBCheck(RECT rect1, RECT rect2)
{
	return !(rect1.right < rect2.left || rect1.left > rect2.right 
		|| rect1.bottom < rect2.top || rect1.top > rect2.bottom);
}

RECT CPhysicalSystem::GetSweptBroadphaseBox(CObject* obj)
{
	RECT broadphasebox;
	broadphasebox.left = obj->GetVelocity().x > 0 ? obj->GetBond().left : obj->GetBond().left + obj->GetVelocity().x;
	broadphasebox.top = obj->GetVelocity().y > 0 ? obj->GetBond().top : obj->GetBond().top + obj->GetVelocity().y;
	broadphasebox.right = obj->GetVelocity().x > 0 ? obj->GetBond().right + obj->GetVelocity().x : obj->GetBond().right;
	broadphasebox.bottom = obj->GetVelocity().y > 0 ? obj->GetBond().bottom + obj->GetVelocity().y : obj->GetBond().bottom;
	return broadphasebox;
}
// performs collision detection on moving box b1 and static box b2
// returns the time that the collision occured (where 0 is the start of the movement and 1 is the destination)
// getting the new position can be retrieved by box.x = box.x + box.vx * collisiontime
// normalx and normaly return the normal of the collided surface (this can be used to do a response)
float CPhysicalSystem::SweptAABB(CObject *obj1, CObject *obj2)
{
	float xInvEntry, yInvEntry;
	float xInvExit, yInvExit;

	// find the distance between the objects on the near and far sides for both x and y
	if (obj1->GetVelocity().x > 0.0f)
	{
		xInvEntry = obj2->GetBond().left - obj1->GetBond().right;
		xInvExit = obj2->GetBond().right - obj1->GetBond().left;
	}
	else 
	{
		xInvEntry = obj2->GetBond().right - obj1->GetBond().left;
		xInvExit = obj2->GetBond().left - obj1->GetBond().right;
	}

	if (obj1->GetVelocity().y > 0.0f)
	{
		yInvEntry = obj2->GetBond().top - obj1->GetBond().bottom;
		yInvExit = obj2->GetBond().bottom - obj1->GetBond().top;
	}
	else
	{
		yInvEntry = obj2->GetBond().bottom - obj1->GetBond().top;
		yInvExit = obj2->GetBond().top - obj1->GetBond().bottom;
	}

	// find time of collision and time of leaving for each axis (if statement is to prevent divide by zero)
	float xEntry, yEntry;
	float xExit, yExit;

	if (obj1->GetVelocity().x == 0.0f)
	{
		xEntry = -std::numeric_limits<float>::infinity();
		xExit = std::numeric_limits<float>::infinity();
	}
	else
	{
		xEntry = xInvEntry / obj1->GetVelocity().x;
		xExit = xInvExit / obj1->GetVelocity().x;
	}

	if (obj1->GetVelocity().y == 0.0f)
	{
		yEntry = -std::numeric_limits<float>::infinity();
		yExit = std::numeric_limits<float>::infinity();
	}
	else
	{
		yEntry = yInvEntry / obj1->GetVelocity().y;
		yExit = yInvExit / obj1->GetVelocity().y;
	}

	// find the earliest/latest times of collision
	float entryTime = max(xEntry, yEntry);
	float exitTime = min(xExit, yExit);

	// if there was no collision
	if (entryTime > exitTime || xEntry < 0.0f && yEntry < 0.0f || xEntry > 1.0f || yEntry > 1.0f)
	{
		return 1.0f;
	}
	else // if there was a collision
	{        	
		// return the time of collision
		return entryTime;
	}
}

void CPhysicalSystem::MoveAABB(CObject *obj1, CObject *obj2, float gameTime, CInput* input)
{
	RECT broadphasebox = GetSweptBroadphaseBox(obj1);
	if (AABBCheck(broadphasebox, obj2->GetBond()))
	{
		float collisiontime = SweptAABB(obj1, obj2);
		float remainingtime = 1.0f - collisiontime;
		obj1->UpdatePosition(collisiontime);
		if (collisiontime < 1.0f)
		{
			// perform response here
			if (obj1->GetBond().top >= obj2->GetBond().bottom)		//obj1 di tu duoi obj2 len //nhay len
			{
				obj1->SetVelocityY(-1 * obj1->GetVelocity().y);
				obj1->UpdatePosition(remainingtime);
			} 
			else if (obj1->GetBond().bottom <= obj2->GetBond().top)	//obj1 di tu tren obj2 xun // roi xuong
			{
				float temp = obj1->GetVelocity().y;
				obj1->SetVelocityY(0);
				obj1->UpdatePosition(remainingtime);
				//obj1->SetVelocityY(temp);
			} 
			else
			{
				return;
			}
		}
	}
	else
	{
		obj1->UpdatePosition(1.0f);
	}
	obj1->Update(gameTime,input);
}